/*
	Last change:  RM   17 Jan 2001   20:15
*/

//*****************************************************************************
//
//      COPYRIGHT (c) ATMEL Norway, 1996-2001
//
//      The copyright to the document(s) herein is the property of
//      ATMEL Norway, Norway.
//
//      The document(s) may be used  and/or copied only with the written
//      permission from ATMEL Norway or in accordance with the terms and
//      conditions stipulated in the agreement/contract under which the
//      document(s) have been supplied.
//
//*****************************************************************************
//
//  File........: DATAFLASH.C
//
//  Author(s)...: ATMEL Norway
//
//  Target(s)...: All AVRs with built-in HW SPI
//
//  Description.: Functions to access the Atmel AT45Dxxx dataflash series
//				  Supports 512Kbit - 64Mbit
//
//  Revisions...:
//
//  YYYYMMDD - VER. - COMMENT                                       - SIGN.
//
//  20011017 - 1.00 - Beta release                                  -  RM
//  20011017 - 0.10 - Generated file                                -  RM
//  20031009          port to avr-gcc/avr-libc                      - M.Thomas
//
//*****************************************************************************

// Includes
//mtA
//#include <INA90.H>
//#include "iom169.h"
#include <avr/io.h>
#include <inttypes.h>
#include <avr/pgmspace.h>
//mtE

#include "..\SPI\SPI.h"
#include "dataflash.h"

// Constants
//Look-up table for these sizes ->  512k, 1M, 2M, 4M, 8M, 16M, 32M, 64M
// mt flash uint8_t df_page_bits_array[]  ={  9,  9,  9,  9,  9,  10,  10,  11};	    //index of internal page address bits
const uint8_t df_page_bits_array[] PROGMEM ={  9,  9,  9,  9,  9,  10,  10,  11};	    //index of internal page address bits
//Look-up table for these sizes ->  512k, 1M,  2M,  4M,  8M, 16M, 32M, 64M
// mt flash uint16_t  df_page_size_array[]  ={264,264, 264, 264, 264, 528, 528,1056};	//index of page_sizes
const uint16_t df_page_size_array[] PROGMEM ={264,264, 264, 264, 264, 528, 528,1056};	//index of page_sizes

// Functions

	


/*****************************************************************************
*
*	Function name : Read_DF_status
*
*	Returns :		One status byte. Consult Dataflash datasheet for further
*					decoding info
*
*	Parameters :	None
*
*	Purpose :		Status info concerning the Dataflash is busy or not.
*					Status info concerning compare between buffer and flash page
*					Status info concerning size of actual device
*
******************************************************************************/
/*!	
	\brief Reads the DataFlash Status register for
	<li> Ready or Busy bit
	<li> Results of comparing buffer to page
	<li> DataFlash size

	\param None

	\returns The Status byte
*/
uint8_t df_read_status (void)
{
	uint8_t result,index_copy;
	
	// Toggle SS to reset DataFlash command decoder
	spi0_SS();
	
	// Send opcode to read the status register
	result = spi0_master_rw8(StatusReg);
	// Send a dummy byte to receive the results
	result = spi0_master_rw8(0x00);
	
	// Get the size information
	index_copy = ((result & 0x38) >> 3);

	// Get the nuber of internal page address bits from the lookup table
	df_page_bits   = pgm_read_byte(&df_page_bits_array[index_copy]);
	// Get the size of the page (in bytes)
	df_page_size   = pgm_read_word(&df_page_size_array[index_copy]);   

	// Return the status register value
	return result;
}


/*****************************************************************************
*
*	Function name : Page_To_Buffer
*
*	Returns :		None
*
*	Parameters :	df_buffer_no	->	Decides usage of either buffer 1 or 2
*					df_page_adr		->	Address of page to be transferred to buffer
*
*	Purpose :		Transfers a page from flash to dataflash SRAM buffer
*					
******************************************************************************/
/*!	
	\brief Transfers a DataFlash page to one of the SRAM buffers
 
	\param df_buffer_no - Buffer number 1 or 2
	\param df_page_adr - Flash page address to be transferred

	\returns Nothing
*/
void df_page_to_buffer (uint16_t df_page_adr, uint8_t df_buffer_no)
{
	// Toggle slave select
	spi0_SS();
	
	if (1 == df_buffer_no) // Transfer flash page to buffer 1
	{
		spi0_master_rw8(FlashToBuf1Transfer);
	}
	else if (2 == df_buffer_no) // Transfer flash page to buffer 2
	{
		spi0_master_rw8(FlashToBuf2Transfer);
	}

	//Send upper part of page address
	spi0_master_rw8((uint8_t)(df_page_adr >> (16 - df_page_bits)));	
	// Send lower part of page address
	spi0_master_rw8((uint8_t)(df_page_adr << (df_page_bits - 8)));	
	// Dummy write
	spi0_master_rw8(0x00);


	// Toggle slave select
	spi0_SS();
	
	while(!(df_read_status() & 0x80));							//monitor the status register, wait until busy-flag is high
}



/*****************************************************************************
*
*	Function name : Buffer_Read_Byte
*
*	Returns :		One read byte (any value)
*
*	Parameters :	df_buffer_no	->	Decides usage of either buffer 1 or 2
*					df_int_page_adr	->	Internal page address
*
*	Purpose :		Reads one byte from one of the dataflash
*					internal SRAM buffers
*
******************************************************************************/
/*!	
	\brief Reads a byte from on of the DataFlash SRAM buffers

	\param df_buffer_no - Buffer number 1 or 2
	\param df_int_page_adr - Internal page address

	\returns The byte read
*/
uint8_t df_buffer_read_byte (uint8_t df_buffer_no, uint16_t df_int_page_adr)
{
/*	uint8_t data = '0';
		
	// Toggle slave select
	spi0_hard_SS();
	
	if (1 == df_buffer_no) // Read byte from buffer 1
	{
		spi0_master_rw8(Buf1Read);
	}
	else if (2 == df_buffer_no)	// Read byte from buffer 2
	{
		spi0_master_rw8(Buf2Read);
	}

	// Send dummy byte
	spi0_master_rw8(0x00);
	// Send upper part of internal buffer address
	spi0_master_rw8((uint8_t)(df_int_page_adr>>8));
	// Send lower part of internal buffer address
	spi0_master_rw8((uint8_t)(df_int_page_adr));
	// Send dummy byte	
	spi0_master_rw8(0x00);
	// Receive byte
	data = spi0_master_rw8(0x00);
*/
	uint8_t buffer_ptr[] = {'0'};

	df_buffer_read_str (df_buffer_no, df_int_page_adr, 1, buffer_ptr);

	
	// And return it
	return buffer_ptr[0];//data;
}

/*****************************************************************************
*
*	Function name : Buffer_Read_Str
*
*	Returns :		None
*
*	Parameters :	df_buffer_no	->	Decides usage of either buffer 1 or 2
*					df_int_page_adr	->	Internal page address
*					No_of_bytes	->	Number of bytes to be read
*					*BufferPtr	->	address of buffer to be used for read bytes
*
*	Purpose :		Reads one or more bytes from one of the dataflash
*					internal SRAM buffers, and puts read bytes into
*					buffer pointed to by *BufferPtr
*
******************************************************************************/
/*!	
	\brief Reads one or more bytes from the DataFlash SRAM buffers 

	\param df_buffer_no - Buffer to read
	\param df_int_page_adr - Internal page address
	\param no_of_bytes - Number of bytes to read
	\param *buffer_ptr - Address of AVR buffer to hold bytes read

	\returns Nothing
*/
void df_buffer_read_str (uint8_t df_buffer_no, uint16_t df_int_page_adr, uint16_t no_of_bytes, uint8_t *buffer_ptr)
{
	uint16_t i;

	// Toggle slave select
	spi0_SS();
	
	if (1 == df_buffer_no)// Read byte(s) from buffer 1
	{
		spi0_master_rw8(Buf1Read);
	}
	else if (2 == df_buffer_no)// Read byte(s) from buffer 2
	{
		spi0_master_rw8(Buf2Read);
	}

	// Send dummy
	spi0_master_rw8(0x00);
	// Send upper part of internal buffer address
	spi0_master_rw8((uint8_t)(df_int_page_adr>>8));
	// Send lower part of internal buffer address
	spi0_master_rw8((uint8_t)(df_int_page_adr));	
	// Send dummy
	spi0_master_rw8(0x00);
	
	for( i=0; i<no_of_bytes; i++)
	{
		*(buffer_ptr) = spi0_master_rw8(0x00);		//read byte and put it in AVR buffer pointed to by *BufferPtr
		buffer_ptr++;						//point to next element in AVR buffer
	}
}




/*****************************************************************************
*
*	Function name : Buffer_Write_Enable
*
*	Returns :		None
*
*	Parameters :	df_int_page_adr	->	Internal page address to start writing from
*					BufferAdr	->	Decides usage of either buffer 1 or 2
*					
*	Purpose :		Enables continous write functionality to one of the dataflash buffers
*					buffers. NOTE : User must ensure that CS goes high to terminate
*					this mode before accessing other dataflash functionalities 
*
******************************************************************************/
/*!	
	\brief Enables a continuous write to one of the SRAM buffers

	\note User must ensure that the slave select line goes high to terminate this mode
	before accessing other DataFlash functionalities

	\param df_int_page-adr - Internal page address
	\param df_buffer_no - Buffer number 1 or 2

	\returns 
*/
void df_buffer_write_enable (uint8_t df_buffer_no, uint16_t df_int_page_adr)
{
	// Toggle slave select
	spi0_SS();
	
	if (1 == df_buffer_no)							//write enable to buffer 1
	{
		spi0_master_rw8(Buf1Write);					//buffer 1 write op-code
	}
	else if (2 == df_buffer_no)							//write enable to buffer 2
	{
		spi0_master_rw8(Buf2Write);					//buffer 2 write op-code
	}

	// Send dummy byte
	spi0_master_rw8(0x00);
	// Send upper part of internal buffer address
	spi0_master_rw8((uint8_t)(df_int_page_adr>>8));
	// Send lower part of internal buffer address
	spi0_master_rw8((uint8_t)(df_int_page_adr));
}



/*****************************************************************************
*
*	Function name : Buffer_Write_Byte
*
*	Returns :		None
*
*	Parameters :	df_int_page_adr	->	Internal page address to write byte to
*					BufferAdr	->	Decides usage of either buffer 1 or 2
*					Data		->	Data byte to be written
*
*	Purpose :		Writes one byte to one of the dataflash
*					internal SRAM buffers
*
******************************************************************************/
/*!	
	\brief Writes one byte to one of the DataFlash SRAM buffers

	\param df_buffer_no - Write to buffer number 1 or 2
	\param df_int_page_adr - Internal page address to werite byte to
	\param data_byte - Data to write

	\returns Nothing
*/
void df_buffer_write_byte (uint8_t df_buffer_no, uint16_t df_int_page_adr, uint8_t data_byte)
{
/*	
	//df_ss_inactive;								//make sure to toggle CS signal in order
	//df_ss_active;								//to reset dataflash command decoder
	spi0_hard_SS();
	
	if (1 == df_buffer_no)							//write byte to buffer 1
	{
		spi0_master_rw8(Buf1Write);					//buffer 1 write op-code
		spi0_master_rw8(0x00);						//don't cares
		spi0_master_rw8((uint8_t)(df_int_page_adr>>8));//upper part of internal buffer address
		spi0_master_rw8((uint8_t)(df_int_page_adr));	//lower part of internal buffer address
		spi0_master_rw8(Data);						//write data byte
	}

//#ifdef USE_BUFFER2
	else
	if (2 == df_buffer_no)							//write byte to buffer 2
	{
		spi0_master_rw8(Buf2Write);					//buffer 2 write op-code
		spi0_master_rw8(0x00);						//don't cares
		spi0_master_rw8((uint8_t)(df_int_page_adr>>8));//upper part of internal buffer address
		spi0_master_rw8((uint8_t)(df_int_page_adr));	//lower part of internal buffer address
		spi0_master_rw8(Data);						//write data byte
	}		
//#endif
*/
	// Enable buffer write
	df_buffer_write_enable (df_buffer_no, df_int_page_adr);
	// Send a data byte
	spi0_master_rw8(data_byte);


}


/*****************************************************************************
*
*	Function name : Buffer_Write_Str
*
*	Returns :		None
*
*	Parameters :	df_buffer_no	->	Decides usage of either buffer 1 or 2
*					df_int_page_adr	->	Internal page address
*					No_of_bytes	->	Number of bytes to be written
*					*BufferPtr	->	address of buffer to be used for copy of bytes
*									from AVR buffer to dataflash buffer 1 (or 2)
*
*	Purpose :		Copies one or more bytes to one of the dataflash
*					internal SRAM buffers from AVR SRAM buffer
*					pointed to by *BufferPtr
*
******************************************************************************/
/*!	
	\brief Writes one or more bytes to the indicated SRAM buffer

	\param df_buffer_no - use buffer 1 or 2 
	\param df_int_page_adr - Internal page address
	\param no_of_bytes - Number of bytes to write
	\param *buffer_ptr - address of the AVR buffer containing the data to be written to the DataFlash buffer

	\returns Nothing
*/

void df_buffer_write_str (uint8_t df_buffer_no, uint16_t df_int_page_adr, uint16_t no_of_bytes, uint8_t *buffer_ptr)
{
	uint16_t i;

/*	// Toggle slave select
	spi0_hard_SS();
	
	// Write to buffer 1
	if (1 == df_buffer_no) //write byte(s) to buffer 1
	{
		// Send buffer 1 opcode
		spi0_master_rw8(Buf1Write); 
	}
	else if (2 == df_buffer_no)// Write to Buffer 2	
	{
		// Send buffer 2 opcode
		spi0_master_rw8(Buf2Write);
	}

	//Send dummy
	spi0_master_rw8(0x00); 
	// Send upper part of buffer address
	spi0_master_rw8((uint8_t)(df_int_page_adr>>8));
	// Send lower part of buffer address
	spi0_master_rw8((uint8_t)(df_int_page_adr)); 
*/

	// Enable buffer write
	df_buffer_write_enable (df_buffer_no, df_int_page_adr);
	
	// Send the data	
	for( i=0; i<no_of_bytes; i++)
	{
		// Write byte pointed at by *BufferPtr
		spi0_master_rw8(*(buffer_ptr));
		// Point to next byte
		buffer_ptr++;						
	}
}


/*****************************************************************************
*
*	Function name : Buffer_To_Page
*
*	Returns :		None
*
*	Parameters :	BufferAdr	->	Decides usage of either buffer 1 or 2
*					df_page_adr		->	Address of flash page to be programmed
*
*	Purpose :		Transfers a page from dataflash SRAM buffer to flash
*					
******************************************************************************/
/*!	
	\brief Transfers a page from the SRAM buffer to Flash.

	\param df_buffer_no - Selects buffer number
	\param df_page_addr - Address of flash page to be programmed

	\returns None
*/
void df_buffer_to_page (uint8_t df_buffer_no, uint16_t df_page_adr)
{
	// Toggle slave select
	spi0_SS();

	if (1 == df_buffer_no)// Write flash page from buffer 1
	{
		spi0_master_rw8(Buf1ToFlashWE);
	}
	else if (2 == df_buffer_no)// Write flash page from buffer 2
	{
		spi0_master_rw8(Buf2ToFlashWE);
	}

	// Write upper part of page address
	spi0_master_rw8((uint8_t)(df_page_adr >> (16 - df_page_bits)));	
	// Write lower part of page address
	spi0_master_rw8((uint8_t)(df_page_adr << (df_page_bits - 8)));	
	// Send dummy
	spi0_master_rw8(0x00);
	
	// Toggle slave select
	spi0_SS();
	
	// Block until busy-flag is high
	while(!(df_read_status() & 0x80));
}


/*****************************************************************************
*
*	Function name : Cont_Flash_Read_Enable
*
*	Returns :		None
*
*	Parameters :	df_page_adr		->	Address of flash page where cont.read starts from
*					df_int_page_adr	->	Internal page address where cont.read starts from
*
*	Purpose :		Initiates a continuous read from a location in the DataFlash
*					
******************************************************************************/
/*!	
	\brief Begins a continuous read from a location in DataFlash.T.

	\param df_page_adr - Start continuous read from this flash page address
	\param df_int_page_addr - Start continuous read from this internal page address

	\returns None
*/
void Cont_Flash_Read_Enable (uint16_t df_page_adr, uint16_t df_int_page_adr)
{
	// Toggle slave select
	spi0_SS();

	//Send Continuous Array Read op-code
	spi0_master_rw8(ContArrayRead);
	// Send upper part of page address
	spi0_master_rw8((uint8_t)(df_page_adr >> (16 - df_page_bits)));	
	//Send lower part of page address and MSB of int.page adr.
	spi0_master_rw8((uint8_t)((df_page_adr << (df_page_bits - 8))+ (df_int_page_adr>>8)));	
	// Send LSB byte of internal page address
	spi0_master_rw8((uint8_t)(df_int_page_adr));
	
	// Perform 4 dummy writes in order to 
	// address pointers
	spi0_master_rw8(0x00);
	spi0_master_rw8(0x00);
	spi0_master_rw8(0x00);
	spi0_master_rw8(0x00);
}

// *****************************[ End Of DATAFLASH.C ]*************************
